﻿using SPWebShell.entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Web.Services.Protocols;

namespace SPWebShell.cmdlet
{
    /// <summary>
    /// Retrieves items from the specified List
    /// </summary>
    [Cmdlet(VerbsCommon.Get, "SPListItem")]
    public class GetSPListItemCmdLet : CmdLetBase
    {

        public GetSPListItemCmdLet()
        {
            this.DatesInUtc = true;
            this.IncludeMandatoryColumns = true;
        }
        [Parameter(Mandatory = true, HelpMessage = "The title of the List")]
        [ValidateNotNullOrEmpty]
        public string List { get; set; }
        
        [Parameter(Mandatory = true, HelpMessage="The absolute URL to the web site where the List is located or any item/view within the List. e.g. http://server/sites/SiteA/doclib1/Allitems.aspx")]
        [ValidateNotNullOrEmpty]
        public string Url { get; set; }

        [Parameter(Mandatory = true, HelpMessage = "All items >=ID will be fetched. Default=0. To fetch a specific ID, use MaxCount=1")]
        [Alias("SPID")]
        public Int32 ID { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "Specifies an array of fields to fetch")]
        [Alias("Properties", "Property")]
        public string[] ViewFields { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "When set to True all dates will be fetched relative to UTC time zone. Default is True")]
        [Alias("utc")]
        public bool DatesInUtc { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "When set to True all mandatory columns will be fetched. Default is True")]
        [Alias("mandatorycolumns")]
        public bool IncludeMandatoryColumns { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "When set to True the underlying XML is dumped to the file specified by property File")]
        public bool Dump { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "The name of the file where the raw contents will be optionally written to when Dump=True")]
        public string File { get; set; }

        protected override void ProcessRecord()
        {
            try
            {
                VerboseLogger("Start time: " + DateTime.Now.ToString());
                ISPRepository repos = base.SPRepos;
                SPDoclibLocation location = repos.ResolveDoclibUrlFromPageUrl(this.Url);
                //If a List name has been provided then use this name
                if (!string.IsNullOrEmpty(this.List)) location.DoclibName = this.List;
                entity.SPList listInfo = this.GetListInfo(location);
                PurifyFieldNames(listInfo);
                VerboseLogger("Querying for item with ID:" + this.ID);
                //SPListItem item = repos.GetListItem(location, this.ID, 1,this.ViewFields,false,"");
                string dumpfile="";
                if (this.Dump)
                {
                    dumpfile=base.GetFullPathToFile(this.File);
                }
                string caml = string.Format("<Where><Eq><FieldRef Name='ID'/><Value Type='Counter'>{0}</Value></Eq>" + "</Where>", this.ID);
                SPListItem[] items = repos.GetListItemsEx(location, 1, this.ViewFields, caml, null, this.DatesInUtc, "", this.IncludeMandatoryColumns, false, this.Dump, dumpfile);
                if ((items == null) || (items.Length == 0) )
                {
                    VerboseLogger("Results - No records found with this ID");
                    WriteObject(null);
                }
                else
                {
                    SPListItem item = items[0];
                    VerboseLogger("Results - match found");
                    PSObject o1 = new PSObject();
                    o1.Members.Add(new PSNoteProperty("ID", item.SPID));
                    o1.Members.Add(new PSNoteProperty("Name", item.Name));
                    foreach (string fieldName in item.FieldValues.Keys)
                    {
                        Object fieldValue = item.FieldValues[fieldName];
                        o1.Members.Add(new PSNoteProperty(fieldName, fieldValue));
                    }
                    WriteObject(o1);
                }
                VerboseLogger("End time: " + DateTime.Now.ToString());
                base.ProcessRecord();
            }
            catch (SoapException ex)
            {
                string message = ex.Detail.OuterXml;
                throw new Exception(message, ex);
            }
            finally
            {
                WriteVerbose("End time: " + DateTime.Now.ToString());
            }

        }
        entity.SPList GetListInfo(SPDoclibLocation listlocation)
        {
            this.VerboseLogger("Fetching metadata for the list:" + listlocation.DoclibName);
            entity.SPList listInfo = null;
            listInfo = base.SPRepos.GetList(listlocation);
            this.VerboseLogger("Metadata obtained:");
            return listInfo;            
        }
        private void PurifyFieldNames(entity.SPList listInfo)
        {
            if (this.ViewFields == null) return;
            if (this.ViewFields.Length == 0) return;
            List<string> purifiedpropnames = new List<string>();
            foreach (string propname in this.ViewFields)
            {
                if (string.IsNullOrEmpty(propname)) throw new Exception("Cannot accept NULL property names");
                string propnametrimmed = propname.Trim();
                entity.SPField thisField = listInfo.Fields.FirstOrDefault(f => (f.InternalName.Equals(propnametrimmed, StringComparison.CurrentCultureIgnoreCase)));
                if (thisField == null) throw new Exception(string.Format("No property found with the name:{0}", propnametrimmed));
                purifiedpropnames.Add(thisField.InternalName);
            }
            this.ViewFields = purifiedpropnames.ToArray();
        }
    }
}
